package com.moliku.insurance.common.exception;


import cn.hutool.core.util.StrUtil;
import com.moliku.insurance.common.response.CommonInsureResult;
import com.moliku.insurance.common.response.R;
import com.moliku.insurance.common.response.ResponseCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.DispatcherServlet;

import javax.servlet.Servlet;

/**
 * 全局异常处理，处理可预见的异常
 * ResponseStatus在此用于表示网络请求状态
 * R中code 表示业务状态码，success 表示该操作是否操作成功
 *
 * @author Mr.Liu
 * @since 2020-02-01
 */
@Slf4j
@Configuration
@ConditionalOnClass({Servlet.class, DispatcherServlet.class})
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@RestControllerAdvice
public class RestExceptionTranslator {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public R<Object> handleErrorMessage(MethodArgumentNotValidException e) {
        log.error("参数验证失败：{}", e.getMessage());
        return R.fail(handleErrorMessage(e.getBindingResult()), ResponseCode.PARAM_VALID_ERROR);
    }

    @ExceptionHandler(BindException.class)
    public R<Object> handleErrorMessage(BindException e) {
        log.error("参数绑定验证失败：{}", e.getMessage());
        return R.fail(handleErrorMessage(e.getBindingResult()), ResponseCode.PARAM_VALID_ERROR);
    }

    @ExceptionHandler(HttpMessageNotReadableException.class)
    public R<Object> handleHttpRequestMessage(HttpMessageNotReadableException e) {
        log.error("参数序列化失败：{}", e.getMessage());
        return R.fail("请检查请求参数", ResponseCode.PARAM_VALID_ERROR);
    }

    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public R<Object> handleHttpRequestMessage(HttpRequestMethodNotSupportedException e) {
        log.error("不支持的请求方法：{}", e.getMessage());
        return R.fail("不支持的请求方法", ResponseCode.PARAM_VALID_ERROR);
    }

    @ExceptionHandler(SubmitPolicyException.class)
    public R<Object> handleServiceException(SubmitPolicyException e) {
        log.error("投保失败", e);
        CommonInsureResult result = CommonInsureResult.submitPolicyFail(e);
        return R.data(result.getSubmitPolicyResult());
    }

    @ExceptionHandler(CancelPolicyException.class)
    public R<Object> handleServiceException(CancelPolicyException e) {
        log.error("退保失败", e);
        CommonInsureResult result = CommonInsureResult.cancelPolicyFail(e);
        return R.data(result.getCancelPolicyResult());
    }

    @ExceptionHandler(DownloadPolicyException.class)
    public R<Object> handleServiceException(DownloadPolicyException e) {
        log.error("下载失败", e);
        CommonInsureResult result = CommonInsureResult.downloadPolicyFail(e);
        return R.data(result.getDownloadPolicyResult());
    }

    @ExceptionHandler(ServiceException.class)
    public R<Object> handleServiceException(ServiceException e) {
        log.error("业务异常", e);
        String msg = StrUtil.blankToDefault(e.getMessage(), ResponseCode.PARAM_VALID_ERROR.getMessage());
        return R.fail(msg, e.getResponseCode());
    }

    @ExceptionHandler(Throwable.class)
    public R<Object> handleErrorMessage(Throwable e) {
        e.printStackTrace();
        return R.fail("网络数据异常，请稍后再试", ResponseCode.UNKNOWN_ERROR);
    }

    private String handleErrorMessage(BindingResult result) {
        FieldError error = result.getFieldError();
        return error != null ? error.getDefaultMessage() : "";
    }
}